package cn.falcon.fmobi.console.controller;

import cn.falcon.fmobi.biz.common.ResultSetList;
import cn.falcon.fmobi.biz.service.AgentService;
import cn.falcon.fmobi.biz.service.CustomerService;
import cn.falcon.fmobi.biz.service.FinancialService;
import cn.falcon.fmobi.biz.vo.AccountBalanceVo;
import cn.falcon.fmobi.biz.vo.AccountParam;
import cn.falcon.fmobi.biz.vo.FmobiUser;
import cn.falcon.fmobi.console.aop.ResultCode;
import cn.falcon.fmobi.console.common.RestfulJsonModelAndView;
import cn.falcon.fmobi.console.common.Result;
import cn.falcon.fmobi.console.constant.UrlConstant;
import cn.falcon.fmobi.console.constant.UserRolePermission;
import cn.falcon.fmobi.console.exception.CallBackException;
import cn.falcon.fmobi.console.exception.ParamValidateException;
import cn.falcon.fmobi.console.requestparam.FinanceQuery;
import cn.falcon.fmobi.dao.enumration.AccountDealType;
import cn.falcon.dmp.po.AccountCostDetail;
import cn.falcon.fmobi.dao.model.AccountFlowModel;
import cn.falcon.fmobi.dao.po.Advertiser;
import cn.falcon.fmobi.dao.po.Agent;
import cn.falcon.fmobi.dao.po.Finance;
import cn.falcon.fmobi.dao.util.DataUtils;
import cn.falcon.fmobi.dao.util.ValidateUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.Map;

/**
 * 财务管理模块
 * @author zhaohelong
 * @date 2017-11-07
 */
@Controller
@RequestMapping(UrlConstant.FINANCIAL_URL)
public class FinancialCtrl extends BaseCtrl {

    @Autowired
    private FinancialService financialService;
    @Autowired
    private AgentService agentService;
    @Autowired
    private CustomerService customerService;


    /**
     * 查询广告主或当前登录账户余额
     * @param advertiserId 广告主ID 缺省时默认查询当前登录账户
     * @return
     */
    @RequestMapping(value = "/balance",method = RequestMethod.GET)
    public ModelAndView getBalance(@RequestParam(value = "advertiserId") Integer advertiserId, HttpSession session){
        //如果advertiserId不为空则查询广告主账户余额
        if (advertiserId!=null&&advertiserId!=0){
            AccountBalanceVo balance = financialService.getBalance(advertiserId,true);
            return RestfulJsonModelAndView.buildJsonModelAndView(balance);
        }else{
            //否则则查询当前登录账户的余额
            FmobiUser fmobiUser = readSession(session);
            //如果当前账户角色为广告主
            if (fmobiUser.getRole().equals(UserRolePermission.USER_ROLE_ADVERTISER)){
                AccountBalanceVo balance = financialService.getBalance(fmobiUser.getId(),true);
                return RestfulJsonModelAndView.buildJsonModelAndView(balance);
            }else{
                AccountBalanceVo balance = financialService.getBalance(fmobiUser.getId(),false);
                return RestfulJsonModelAndView.buildJsonModelAndView(balance);
            }
        }
    }

    /**
     * 广告主划账列表
     * @param query 查询条件
     * @param session 请求会话
     * @return
     */
    @RequestMapping(value = "/financeList",method = RequestMethod.GET)
    public ModelAndView getAdvertiserList(FinanceQuery query,HttpSession session){
        FmobiUser user = readSession(session);
        query.setAgentId(user.getId());
        ResultSetList<Finance> list = financialService.getFinaceListByAgentId(query.getMap(), query.getPageInfo());
        return RestfulJsonModelAndView.buildJsonModelAndView(list);
    }

    /**
     * 转入资金：代理商——>广告主划账
     * @param param 请求参数
     * @param session
     * @return
     */
    @RequestMapping(value = "/into",method = RequestMethod.POST)
    public ModelAndView intoAmount(AccountParam param, HttpSession session) throws UnsupportedEncodingException, ParamValidateException {
        this.validateParam(param);
        //计算(1-服务费/100)
        BigDecimal k=new BigDecimal(1).subtract(param.getCommission()).divide(new BigDecimal(100));
        //计算实际金额=溢价金额x(1-服务费)
        BigDecimal m=param.getPremiumAmount().multiply(k);
        //校验前端计算的实际值与后端计算的是否相等
        if (m.compareTo(param.getActualAmount())==0){
            //获取当前登录用户
            FmobiUser user = readSession(session);
            BigDecimal amount = param.getActualAmount().multiply(user.getRebate());
            if (amount.compareTo(amount.setScale(2,BigDecimal.ROUND_HALF_UP))!=0){
                throw new CallBackException(ResultCode.AMOUNT_REQUIRE_WHOLE_HUNDRED);
            }
            try {
                Integer agentId = getLoginUser(session)!=null?getLoginUser(session).getAgentId():null;
                if (agentId!=null){
                    if (param.getAdvertiserId()==null||param.getAdvertiserId()==0){
                        throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"advertiserId","Result.err.miss.parameter");
                    }
                    Agent agent = agentService.getAgentById(agentId);
                    if (null==agent){
                        throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"acgency not found","Result.err.miss.parameter");
                    }
                    Advertiser advertiser = customerService.getAdvertiserById(param.getAdvertiserId());
                    if (null==advertiser){
                        throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"advertiser not found","Result.err.miss.parameter");
                    }
                    //判断溢价金额是否大于代理商当前余额
                    AccountBalanceVo balance = financialService.getBalance(agentId, false);
                    if (param.getPremiumAmount().compareTo(balance.getBalanceCrash())>0){
                        throw new CallBackException(ResultCode.AMOUNT_PREMIUM_TOO_MUCH);
                    }
                    param.setAgentId(agentId);
                    //设置两次溢价后的金额为实际扣款金额
                    param.setActualAmount(amount);
                    //执行资金转入操作
                    financialService.intoAmount(param);
                }
            }catch (Exception e){
                throw new CallBackException(e.getMessage());
            }
        }else{
            throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"actualAmount","Result.err.invalid.parameter");
        }
        return RestfulJsonModelAndView.buildJsonModelAndView();
    }

    /**
     * 转出资金：代理商<——广告主 扣钱
     * @param param
     * @param session
     * @return
     */
    @RequestMapping(value = "/out",method = RequestMethod.POST)
    public ModelAndView outAmount(AccountParam param,HttpSession session) throws UnsupportedEncodingException, ParamValidateException {
        this.validateParam(param);
        //计算(1-服务费/100)
        BigDecimal k=new BigDecimal(1).subtract(param.getCommission()).divide(new BigDecimal(100));
        //计算实际金额=溢价金额x(1-服务费)
        BigDecimal m=param.getPremiumAmount().multiply(k);
        //校验前端计算的实际值与后端计算的是否相等
        if (m.compareTo(param.getActualAmount())==0){
            //获取当前登录用户
            FmobiUser user = readSession(session);
            BigDecimal amount = param.getActualAmount().multiply(user.getRebate());
            if (amount.compareTo(amount.setScale(2,BigDecimal.ROUND_HALF_UP))!=0){
                throw new CallBackException(ResultCode.AMOUNT_REQUIRE_WHOLE_HUNDRED);
            }
            try {
                Integer agentId = getLoginUser(session)!=null?getLoginUser(session).getAgentId():null;
                if (agentId!=null){
                    if (param.getAdvertiserId()==null||param.getAdvertiserId()==0){
                        throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"advertiserId","Result.err.miss.parameter");
                    }
                    Agent agent = agentService.getAgentById(agentId);
                    if (null==agent){
                        throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"acgency not found","Result.err.miss.parameter");
                    }
                    Advertiser advertiser = customerService.getAdvertiserById(param.getAdvertiserId());
                    if (null==advertiser){
                        throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"advertiser not found","Result.err.miss.parameter");
                    }
                    //判断溢价金额是否大于广告主当前余额
                    AccountBalanceVo balance = financialService.getBalance(param.getAdvertiserId(), true);
                    if (param.getPremiumAmount().compareTo(balance.getBalanceCrash())>0){
                        throw new CallBackException(ResultCode.AMOUNT_PREMIUM_TOO_MUCH);
                    }
                    param.setAgentId(agentId);
                    //设置两次溢价后的金额为实际扣款金额
                    param.setActualAmount(amount);
                    //获取当前登录用户ID
                    int actorId = getCurrentUser().getActorId();
                    param.setCreator(actorId);
                    //执行资金转入操作
                    financialService.outAmount(param);
                }
            }catch (Exception e){
                throw new CallBackException(e.getMessage());
            }
        }else{
            throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"actualAmount","Result.err.invalid.parameter");
        }
        return RestfulJsonModelAndView.buildJsonModelAndView();
    }

    /**
     * 划账明细
     * @param query
     * @param session
     * @return
     */
    @RequestMapping(value = "/flow/details",method = RequestMethod.GET)
    public ModelAndView accountFlow(FinanceQuery query,HttpSession session){
        Integer agentId = getLoginUser(session) != null ? getLoginUser(session).getAgentId() : null;
        BigDecimal rates = readUserRates(session);
        ResultSetList<AccountFlowModel> list = financialService.getAccountFlowList(query.getMap(), query.getPageInfo());
        for (AccountFlowModel flowModel:list.getList()){
            if (flowModel.getDealType().equals(AccountDealType.INTOAMOUNT.getId())){
                flowModel.setIn(flowModel.getIn().divide(rates,2,BigDecimal.ROUND_HALF_UP));
            }else{
                flowModel.setOut(flowModel.getOut().divide(rates,2,BigDecimal.ROUND_HALF_UP));
            }
        }
        return RestfulJsonModelAndView.buildJsonModelAndView(list);
    }

    /**
     * 消耗明细列表
     * @param query
     * @param session
     * @return
     */
    @RequestMapping(value = "cost/details",method = RequestMethod.GET)
    public ModelAndView getCostDetails(FinanceQuery query,HttpSession session){
        Integer advertiserId = getLoginUser(session) != null ? getLoginUser(session).getAdvertiserId() : null;
        if (null!=advertiserId){
            BigDecimal rates = readUserRates(session);
            Map<String, Object> map = query.getMap();
            map.put("advertiserId",advertiserId);
            ResultSetList<AccountCostDetail> list = financialService.getAccountCostList(map, query.getPageInfo());
            for (AccountCostDetail costDetail:list.getList()){
                costDetail.setCost(costDetail.getCost().divide(rates,2,BigDecimal.ROUND_HALF_UP));
            }
            return RestfulJsonModelAndView.buildJsonModelAndView(list);
        }
        return RestfulJsonModelAndView.buildJsonModelAndView(new ResultSetList<AccountCostDetail>());
    }

    /**
     * 校验转入转出资金时的参数是否合法
     * @param param
     */
    private void validateParam(AccountParam param)throws ParamValidateException,UnsupportedEncodingException{
        if(null == param) {
            throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"all param not empty","Result.err.miss.parameter");
        }
        if (null==param.getPremiumAmount()){
            throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"premiumAmount","Result.err.miss.parameter");
        }
        if (null==param.getActualAmount()){
            throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"actualAmount","Result.err.invalid.parameter");
        }
        if (!DataUtils.isNull(param.getDescription()) && ValidateUtil.checkLength(param.getDescription(),120)){
            throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"remark","Result.err.invalid.length");
        }
        //溢价金额只能是整数
        if (param.getPremiumAmount().doubleValue()%1!=0){
            throw new ParamValidateException(Result.ERR_INVALID_PARAMETER_ACCOUNT,"remark","Result.err.invalid.parameter");
        }

    }
}
